Property based testing
参考
『実践プロパティベーステスト』
/mrsekut-book-4274068056/034 (第2章 仕様に基づくテスト)
#WIP
『Property-based testing: a new approach to testing for assurance』
https://xuwei-k.github.io/slides/scalaprops/#1
https://scrapbox.io/mrsekut-p/State_Machine_Testing
https://fsharpforfunandprofit.com/posts/property-based-testing-2/
https://fsharpforfunandprofit.com/series/property-based-testing/
https://zenn.dev/asurato/articles/9518197d42208b
Why Property-Based? | fast-check
fast-checkのdocs
ただただランダムに値を生成するのではなく、問題が起きそうな値もやや恣意的に含む
errorに対しては、Shrinkingし、人間が読みやすい報告をする
/mrsekut-book-pbt/055 (3.1 モデル化)
単純で自明な実装と結果を比較する
実装本体はいくらでも最適化すれば良い
例えば、max :: [Int] -> Intのような関数を定義する際に、
自明な実装の方はmax' = last . sortのように定義する
これで、ランダムに生成し、maxとmax'の結果が一致することを確認する
関数の等価性を使ってチェックするのかmrsekut.icon
code:ts
// Properties
test("biggest", () => {
fc.assert(
fc.property(fc.array(fc.float(), { minLength: 1 }), (n) => {
return biggest(n) === modelBiggest(n);
})
);
});
const biggest = (numbers: number[]) => {
return numbers.reduce((acc, curr) => (acc > curr ? acc : curr), -Infinity);
};
// helper
const modelBiggest = (numbers: number[]) => {
return numbers.sort((a, b) => a - b)numbers.length - 1;
};
/mrsekut-book-pbt/058 (3.2 事例テストを汎化する)
普通にExample-based testingをいくつか書き、それを汎化させてgeneratorにする
/mrsekut-book-pbt/060 (3.3 不変条件)
構成要素同士の不変条件を確認する
sortで、
隣り合う2つの要素を比べたときに常に後者が大きくなる
実行の前後で要素数が一致する
など
いくつかの不変条件を組み合わせないと変な実装でも常にpassしてしまう可能性があることに注意する
/mrsekut-book-pbt/063 (3.4 対称プロパティ)
symmetric propeties
対象プロパティ
2つの関数が逆方向に動作する場合、それらを組み合わせて同じ結果になることを確認する
2つである必要もなく、複数の関数が円環に動作するなら使える
e.g.
encode/decode
code:ts
describe("properties", () => {
test("synmetry", () => {
fc.assert(
fc.property(fc.string(), (text) => {
return decode(encode(text)) === text;
})
);
});
});
const encode = (text: string) => text.split("").join(",");
const decode = (encoded: string) => encoded.split(",").join("");
ちなみに上記コードは","という入力を与えたときに失敗する